package com.quark.framework.ormapping;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONObject;

import com.quark.data.type.QuarkVariable;
import com.quark.framework.utility.QuarkLog;
import com.quark.web.ui.field.IQuarkUiField;
import com.quark.web.ui.field.QuarkUiFieldBase;

//reflection base, base for DateEntity and IntrospectClass

//orm config json:
//isUpdateKey, is this key a main key
//referTo, foreigh key
//managerType, for generic manager

public class QuarkOrmEntity implements QuarkOrmHost{

	private Map<String, QuarkOrmProperty<?>> fieldMapping = new HashMap<String, QuarkOrmProperty<?>>();
	private Map<Integer, String> nameMapping = new HashMap<Integer, String>();
	private List<Field> properties = new ArrayList<Field>();
	private QuarkOrmProperty<?> updateKey = null;
	private boolean isModified = false;
	private Map<Class<?>, Object> logics = new HashMap<Class<?>, Object>();
	public QuarkOrmEntity()
	{
		Field[] fields = getClass().getDeclaredFields();
		for(Field f : fields)
		{
			if(f.getType().equals(QuarkOrmProperty.class))
			{
				properties.add(f);
			}
		}
	}
	
	protected void registerLogic(Object logic)
	{
		logics.put(logic.getClass(), logic);
	}
	
	public String getPropName(QuarkOrmProperty<?> property)
	{
		return nameMapping.get(property.hashCode());
	}
	
	@SuppressWarnings("unchecked")
	public boolean addItemMapping(QuarkOrmProperty<?> property)
	{
		int fieldIdx = fieldMapping.size();		
		Field curField = null;
		Class<? extends QuarkOrmEntity> hostClass = getClass();
		List<Class<? extends QuarkOrmEntity>> classList = new ArrayList<Class<? extends QuarkOrmEntity>>();
		while(hostClass != QuarkOrmEntity.class)
		{
			classList.add(hostClass);
			hostClass = (Class<? extends QuarkOrmEntity>)hostClass.getSuperclass();
		}
		for(int j = classList.size() - 1; j >= 0; j --)
		{
			Field[] fields = classList.get(j).getDeclaredFields();
			for(int i = 0; i < fields.length; i++)
			{
				if(fields[i].getType().equals(QuarkOrmProperty.class))
				{
					if(fieldIdx == 0)
					{
						curField = fields[i];
						break;
					}
					else
						fieldIdx --;
				} 
			}
			if(curField != null) 
				break;
	
		}
		if(curField == null)
		{
			QuarkLog.log(new Exception("No " + property.getName() + " found on class " + getClass()));
			return false;
		}
		fieldMapping.put(curField.getName(), property);
		nameMapping.put(property.hashCode(), curField.getName());
		return true;
	}
	
	public boolean hasProperty(String name)
	{
		return fieldMapping.get(name) != null;
	}
	
	public boolean setPropertyValue(String name, Object obj)
	{
		QuarkOrmProperty<?> property = fieldMapping.get(name);
		if(property != null)
		{
			return property.setValue(new QuarkVariable(obj, String.class));			
		}
		else
		{
			return false;
		}
	}
	
	public int getPropertyCount()
	{
		return properties.size();
	}
	
	public Object getPropertyValue(String name)
	{
		QuarkOrmProperty<?> property = fieldMapping.get(name);
		if(property != null)
		{
			return property.getValue();			
		}
		else
		{
			return null;
		}		
	}
	
	public QuarkOrmProperty<?> getProperty(String name)
	{
		return fieldMapping.get(name);
	}
	
	public QuarkOrmProperty<?>[] getAllProperties()
	{
		QuarkOrmProperty<?>[] props = new QuarkOrmProperty<?>[fieldMapping.size()];
		Iterator<QuarkOrmProperty<?>> it = fieldMapping.values().iterator();
		for(int i = 0; it.hasNext(); i++)
		{
			props[i] = it.next();
		}
		return props;
	}
	
	
	
	public int fromMap(Map<String, String> map)
	{
		Iterator<String> it = fieldMapping.keySet().iterator();
		int count = 0;
		while(it.hasNext())
		{
			String key = it.next();
			String value = map.get(key);
			if(value != null)
			{
				if(!setPropertyValue(key, value))
				{
					QuarkLog.logMessage("Set Prop Failed:[" + key + "] = " + value + ".");
				}
				else
				{
					count ++;
				}				
			}
		}
		return count;
	}
	
	public int fromResultSet(ResultSet rst)
	{
		int count = 0;
		try {
			if(rst == null)
				return 0;
			Iterator<String> it = fieldMapping.keySet().iterator();
			while(it.hasNext())
			{
				String key = it.next();
				Object value = rst.getObject(key);
				if(value != null)
				{
					if(!setPropertyValue(key, value))
					{
						QuarkLog.logMessage("Set Prop Failed:[" + key + "] = " + value + ".");
					}
					else
					{
						count ++;
					}
				}
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			QuarkLog.log(e);
		}
		return count;
		
	}
	
	public int fromJSON(JSONObject json)
	{
		if(json.isArray() || json.isEmpty())
			return 0;
		Iterator<String> it = fieldMapping.keySet().iterator();
		int count = 0;
		while(it.hasNext())
		{
			String key = it.next();
			Object value = json.get(key);
			if(value != null)
			{
				if(!setPropertyValue(key, value))
				{
					QuarkLog.logMessage("Set Prop Failed:[" + key + "] = " + value + ".");
				}
				else
				{
					count ++;
				}
			}
		}
		return count;
	}

	public Method[] getMethods()
	{
		return this.getClass().getDeclaredMethods();
	}
	
	public Method[] getPublicMethod()
	{
		return this.getClass().getMethods();
	}

	public boolean hasMethod(String name)
	{
		Method[] methods = getMethods();
		for(Method i : methods)
		{
			if(i.getName() == name)
			{
				return true;
			}
		}
		return false;
	}
	public boolean setUpdateKey(QuarkOrmProperty<?> property) {
		// TODO Auto-generated method stub
		updateKey = property;
		return true;
	}
	public QuarkOrmProperty<?> getUpdateKey()
	{
		return updateKey;
	}
	
	public void setModified(boolean isModified) {
		this.isModified = isModified;
	}
	
	public void eraseModifyMark()
	{
		Iterator<QuarkOrmProperty<?>> it = fieldMapping.values().iterator();
		while(it.hasNext())
		{
			QuarkOrmProperty<?> next = it.next();
			next.clearModifyMark();
		}
		setModified(false);
	}

	public int getModifiedCount()
	{
		Iterator<QuarkOrmProperty<?>> it = fieldMapping.values().iterator();
		int res = 0;
		while(it.hasNext())
		{
			QuarkOrmProperty<?> next = it.next();
			res += next.isModified() ? 1 : 0;
		}
		return res;
	}
	
//data logic interface
	public Object getLogic(Class<?> logicClass)
	{
		return logics.get(logicClass);
	}
	
	public boolean doBeforeInsert()
	{
		return true;
	}
	
	public boolean doAfterInsert()
	{
		eraseModifyMark();
		return true;
	}
	
	public boolean doBeforeUpdate()
	{
		return true;
	}
	
	public boolean doAfterUpdate()
	{
		eraseModifyMark();
		return true;
	}
	
	public boolean doAfterSelect()
	{
		return true;
	}
	
	public boolean doBeforeDelete()
	{
		return true;
	}
	
	public boolean doBeforeReplace()
	{
		return true;
	}
	
	public boolean doAfterReplace()
	{
		return true;
	}


}
